package ast

import (
	"bytes"
	"strings"

	"gitee.com/chuanjinge/go-interpreter-waiig/src/monkey/tok"
)

// 抽象语法树应该是由多个节点构成的一棵树
// 这棵树的节点可能是语句(比如let a=1+1)、表达式(比如1+1)等等

// 定义Node接口，所有的语法树节点都应该实现该接口。
// 现在该接口仅仅有一个功能，就是输出字面量，用作调试使用。
// 实际上该接口是底层接口，真正的语法树节点应该是实现了 Statement/Expression 这种声明了自己是Node对象的类型
type Node interface {
	TokenLiteral() string
	String() string // 将当前节点的结构化转为字符串表示，也就是恢复为文本形式，比如 let a=1+1;
}

// ----------- 更高级的NODE接口
// 语句 节点
type Statement interface {
	Node
	statementNode()
}

// 表达式 节点
type Expression interface {
	Node
	expressionNode()
}

// ----------- 具体节点
// - 程序根节点
type Program struct {
	Statements []Statement // 程序必然包含多个语句
}

func (p *Program) TokenLiteral() string {
	if len(p.Statements) > 0 {
		return p.Statements[0].TokenLiteral() // 输出第一个语句的字面量
	} else {
		return ""
	}
}

func (p *Program) String() string {
	var out bytes.Buffer
	// 根节点恢复为字符串形式的方式就是把每个节点都输出为字符串形式
	for _, stmt := range p.Statements {
		out.WriteString(stmt.String())
	}
	return out.String()
}

// !+[Statement]各种语句

// !+[LET]
// - LET【语句节点】表示
type LetStatement struct {
	Token tok.Token   // 当前语句的关联语法单元，当然let语句肯定是 let那个单元了，此处写成这种通用写法。
	Name  *Identifier // 左值必须是一个标识符，let a=1+2 中的a作为变量名标识符存在；实际上LET语句的标识符是不需要返回值的，虽然标识符类型实现的是Expression
	Value Expression  // 右值必须是一个表达式接口的实现（表达式是有返回值的）
}

// -- LET【语句节点】实现 Statement 接口
func (ls *LetStatement) statementNode()       {}
func (ls *LetStatement) TokenLiteral() string { return ls.Token.Literal }

// Let语句恢复为字符串形式就是 let NAME.string() = VALUE.string()
func (ls *LetStatement) String() string {
	var out bytes.Buffer
	out.WriteString(ls.TokenLiteral() + " ")
	out.WriteString(ls.Name.String())
	out.WriteString(" = ")

	// 再拼接表达式的字符串表达，即 VALUE.string()
	if ls.Value != nil {
		out.WriteString(ls.Value.String())
	}

	out.WriteString(";")
	return out.String()
}

// !-[LET]

// !+[RETURN]
type ReturnStatement struct {
	Token tok.Token
	Value Expression // return语句紧跟着一个表达式（单独的数字也可以看做是一种特殊的表达式）
}

func (rs *ReturnStatement) statementNode()       {}
func (rs *ReturnStatement) TokenLiteral() string { return rs.Token.Literal }

// 恢复为字符串形式表达 return Expression.String()
func (rs *ReturnStatement) String() string {
	var out bytes.Buffer
	out.WriteString(rs.Token.Literal + " ")
	if rs.Value != nil {
		out.WriteString(rs.Value.String())
	}
	out.WriteString(";")
	return out.String()
}

// !-[RETURN]

// !+[ExpressionStatement]
// - 表达式语句
// -- 本来是一个和语句同级的语法结构
// -- 但是表达式本身又可以看做是一个语句，比如这一行就是写了一个 x+5;
type ExpressionStatement struct {
	Token      tok.Token
	Expression Expression
}

func (es *ExpressionStatement) statementNode()       {}
func (es *ExpressionStatement) TokenLiteral() string { return es.Token.Literal }

// 表达式语句恢复为字符串形式
func (es *ExpressionStatement) String() string {
	if es.Expression != nil {
		return es.Expression.String()
	}
	return ""
}

// !-[ExpressionStatement]

// - if/else块语句，该语句有多条子语句构成
type BlockStatement struct {
	Token      tok.Token
	Statements []Statement
}

func (bs *BlockStatement) statementNode()       {}
func (bs *BlockStatement) TokenLiteral() string { return bs.Token.Literal }
func (bs *BlockStatement) String() string {
	str := ""
	for _, s := range bs.Statements {
		str = str + s.String()
	}
	return str
}

// !-[Statement]

// !+[Expression] 各种表达式

// - 标识符表达式
// -- 此处将标识符节点视为一种表达式
// -- 表达式是有值的，但是在 let a=1+2中 a是标识符，但是a实际上是不会返回值的；此处书中说是为了兼容后边，后边有些标识符是会返回值的。
type Identifier struct {
	Token tok.Token // 标识符的关联语法单元，此处类型肯定是 IDENT了，值就是各个变量名
	Value string    // 对于let的标识符来说这个值是没有意义的，因为let的标识符不产生值，但是别的语句有可能;所以统一为字面量即可
}

// -- 实现 Expression 接口
func (i *Identifier) expressionNode()      {}
func (i *Identifier) TokenLiteral() string { return i.Token.Literal }
func (i *Identifier) String() string       { return i.Value }

// - 整数字面量表达式
type IntegerLiteral struct {
	Token tok.Token
	Value int64 // 终于有非string的expression了
}

// -- 实现expression接口
func (il *IntegerLiteral) expressionNode()      {}
func (il *IntegerLiteral) TokenLiteral() string { return il.Token.Literal }
func (il *IntegerLiteral) String() string       { return il.Token.Literal }

// - 布尔字面量
type BoolLiteral struct {
	Token tok.Token
	Value bool
}

func (bl *BoolLiteral) expressionNode()      {}
func (bl *BoolLiteral) TokenLiteral() string { return bl.Token.Literal }
func (bl *BoolLiteral) String() string       { return bl.Token.Literal }

// - 前缀表达式
type PrefixExpression struct {
	Token    tok.Token  // 前缀操作符表示的词法单元节点，比如 ! 或者 -
	Operator string     // 前缀操作符，其实就是 !或者-
	Right    Expression // 前缀表达式在操作符右侧就是另一个表达式
}

// -- 实现expression接口
func (pe *PrefixExpression) expressionNode()      {}
func (pe *PrefixExpression) TokenLiteral() string { return pe.Token.Literal }
func (pe *PrefixExpression) String() string {
	return "(" + pe.Operator + pe.Right.String() + ")"
}

// - 中缀表达式
type InfixExpression struct {
	Token    tok.Token  // 中缀操作符表示的词法单元节点
	Operator string     // 中缀操作符，+=*/ 之类的
	Right    Expression // 中缀表达式在操作符右侧的表达式
	Left     Expression // 中缀表达式在操作符左侧的表达式
}

// -- 实现expression接口
func (ie *InfixExpression) expressionNode()      {}
func (ie *InfixExpression) TokenLiteral() string { return ie.Token.Literal }
func (ie *InfixExpression) String() string {
	return "(" + ie.Left.String() + " " + ie.Operator + " " + ie.Right.String() + ")"
}

// - If表达式
// -- 将if定义为表达式而不是语句，是为了保证if也能有返回值，从而实现 let foobar = if (x>y) {x} else {y}的格式
// -- 感觉有点奇怪!!!
type IfExpression struct {
	Token     tok.Token
	Condition Expression
	// if 结果 （使用一种单独类型的语句表示）
	Consequence *BlockStatement
	// else 结果 （使用一种单独类型的语句表示）
	Alternative *BlockStatement
}

func (ife *IfExpression) expressionNode()      {}
func (ife *IfExpression) TokenLiteral() string { return ife.Token.Literal }
func (ife *IfExpression) String() string {
	str := "if"
	str += ife.Condition.String()
	str += " "
	str += ife.Consequence.String()

	if ife.Alternative != nil {
		str += "else"
		str += ife.Alternative.String()
	}
	return str
}

// - fn函数字面量表达式
type FunctionalLiteral struct {
	Token      tok.Token
	Parameters []*Identifier
	Body       *BlockStatement
}

func (fl *FunctionalLiteral) expressionNode()      {}
func (fl *FunctionalLiteral) TokenLiteral() string { return fl.Token.Literal }
func (fl *FunctionalLiteral) String() string {
	var out bytes.Buffer
	params := []string{}
	for _, p := range fl.Parameters {
		params = append(params, p.String())
	}
	out.WriteString(fl.TokenLiteral())
	out.WriteString("(")
	out.WriteString(strings.Join(params, ", "))
	out.WriteString(")")
	out.WriteString(fl.Body.String())

	return out.String()
}

// - 函数调用表达式
// -- 函数调用包含待调用函数和函数参数列表
type CallExpression struct {
	Token     tok.Token // 课本上此处存在并不是函数名，而是 (
	Function  Expression
	Arguments []Expression // 实参既有可能是字面量，也有可能是表达式
}

func (ce *CallExpression) expressionNode()      {}
func (ce *CallExpression) TokenLiteral() string { return ce.Token.Literal }
func (ce *CallExpression) String() string {
	var out bytes.Buffer
	args := []string{}
	for _, a := range ce.Arguments {
		args = append(args, a.String())
	}

	out.WriteString(ce.Function.String())
	out.WriteString("(")
	out.WriteString(strings.Join(args, ", "))
	out.WriteString(")")

	return out.String()
}

// - 字符串字面量（表达式
// - 词法解析出来的STR的token单元被解析为StringLiteral节点
type StringLiteral struct {
	Token tok.Token
	Value string
}

func (sl *StringLiteral) expressionNode() {}
func (sl *StringLiteral) TokenLiteral() string {
	return sl.Token.Literal
}
func (sl *StringLiteral) String() string {
	return sl.Token.Literal
}

// - 数组
type Array struct {
	Token    tok.Token
	Elements []Expression
}

func (a *Array) expressionNode() {}
func (a *Array) TokenLiteral() string {
	return a.Token.Literal
}
func (a *Array) String() string {
	var out bytes.Buffer
	elements := []string{}
	for _, item := range a.Elements {
		elements = append(elements, item.String())
	}

	out.WriteString("[")
	out.WriteString(strings.Join(elements, ", "))
	out.WriteString("]")

	return out.String()
}

// -- 索引查找数组元素或者字典 的AST节点
type IndexExpression struct {
	Token tok.Token
	Name  Expression // 待索引的数组名称；理论上此处使用 ast.Identity即可，好像没有其他可能-实际上此处也可以是一个数组表达式
	Index Expression // 索引数值; 有可能是各种表达式最后得到的整数值
}

func (ie *IndexExpression) expressionNode() {}
func (ie *IndexExpression) TokenLiteral() string {
	return ie.Token.Literal
}
func (ie *IndexExpression) String() string {
	var out bytes.Buffer
	out.WriteString(ie.Name.String())
	out.WriteString("[")
	out.WriteString(ie.Index.String())
	out.WriteString("]")

	return out.String()
}

// -- 哈希表
type HashLiteral struct {
	Token tok.Token
	Pairs map[Expression]Expression
}

func (hl *HashLiteral) expressionNode()      {}
func (hl *HashLiteral) TokenLiteral() string { return hl.Token.Literal }
func (hl *HashLiteral) String() string {

	var out bytes.Buffer
	elements := []string{}
	for key, value := range hl.Pairs {
		elements = append(elements, key.String()+":"+value.String())
	}

	out.WriteString("{")
	out.WriteString(strings.Join(elements, ", "))
	out.WriteString("}")

	return out.String()
}

// !-[Expression]
